package edu.gatech.aristotle.random.inputGenerator;

import java.io.IOException;
import java.util.Random;

import net.util.File_Handler;

import edu.gatech.aristotle.random.util.CONSTANT_FILE_NAME;
import edu.gatech.aristotle.random.util.CONSTANT_PRINT_TOKEN_INPUT_SPACE;
import edu.gatech.aristotle.random.util.RandomnessSelector;

public class TCAS_RandomInputGenerator implements CONSTANT_PRINT_TOKEN_INPUT_SPACE, CONSTANT_FILE_NAME {
	public String doBatchInput() throws IOException{
		StringBuffer batchInput	= new StringBuffer();
		
		for ( int i = 1; i < NUMBER_OF_TEST_CASE + 1; i ++ ){
			
			String singleInput	= this.doInput();
			
			batchInput.append( singleInput + "\n" );
		}
		

		String testCaseFileName	= experimentDir +
									tcasPath + 
									testCaseNewComingDir + 
									TCAS_TEST_FILE_NAME + 
									TEST_CASE_FILE_POSTFIX;
		File_Handler.write_to_file( testCaseFileName, batchInput.toString() );
		
		return batchInput.toString();
	}
	
	public String doInput(){
		StringBuffer input	= new StringBuffer();
		
		input.append( " " );
		input.append( doArgument_1_Input() + " " );
		input.append( doArgument_2_Input() + " " );
		input.append( doArgument_3_Input() + " " );
		input.append( doArgument_4_Input() + " " );
		input.append( doArgument_5_Input() + " " );
		input.append( doArgument_6_Input() + " " );
		input.append( doArgument_7_Input() + " " );
		input.append( doArgument_8_Input() + " " );
		input.append( doArgument_9_Input() + " " );
		input.append( doArgument_10_Input() + " " );
		input.append( doArgument_11_Input() + " " );
		input.append( doArgument_12_Input() + " " );
		input.append( doArgument_1_Input() + " " );
		input.append( doArgument_1_Input() + " " );
		
		return input.toString();
	}
	
	private int doBoundIntInputWithDistribution( int lowerBound, int lowerIllegal, int upperBound, int upperIllegal, double d ){
		float randomFloat = RandomnessSelector.randomFloat(100);
		
		int input;
		
		int lowerIlegalInput	= new Random().nextInt( lowerBound - lowerIllegal );
		int upperIllegalInput	= new Random().nextInt( upperIllegal - upperBound );
		int legalInput			= new Random().nextInt( upperBound + 1 - lowerBound );
		if ( randomFloat < d ){
			input	= lowerIlegalInput;
		}else if ( randomFloat > ( 1 - d ) ){
			input	= upperIllegalInput;
		}else{
			input	= legalInput;
		}
					
		//return input;
		return legalInput;
	}

	
	private int doBoundIntInput( int lowerBound, int upperBound ){
		int randomVaule	= new Random().nextInt( upperBound - lowerBound );
		
		return randomVaule + lowerBound;
	}
	
	private int doFixedIntInputWithDistribution( int[] fixedInt, double d ){
		
		int input;

		float randomFloat = RandomnessSelector.randomFloat(100);
		if ( randomFloat < d ){
			input	= new Random().nextInt() ;
		}else if ( randomFloat > ( 1 - d ) ){
			input	= new Random().nextInt();
		}else{
			int randomValue	= new Random().nextInt( fixedInt.length );
			input = fixedInt[randomValue%fixedInt.length];
		}
		
//		int randomValue	= new Random().nextInt( fixedInt.length );
//		input = fixedInt[randomValue%fixedInt.length];	
		
		return input;
	}
	/**
	 * randomSeed needs be larger than size of fixedInt.
	 * 
	 * @param fixedInt
	 * @param illegalInt
	 * @param randomSeed
	 * @return
	 */
	private int doFixedIntInput( int[] fixedInt, int[] illegalInt, int randomSeed ){
		int input;
		
		int randomValue	= new Random().nextInt( randomSeed );
		
		if ( randomValue == randomSeed - 1 )
			input = doIllegalInt( illegalInt );		
		else{
			input = fixedInt[randomValue%fixedInt.length];
		}
		
		return input;
	}
	
	private int doIllegalInt(int[] illegalInt) {
		int randomValue	= new Random().nextInt( illegalInt.length );
		
		return illegalInt[randomValue];
	}

	private int doArgument_1_Input(){
		int lowerBound		= 0;
		int lowerIllegal	= -100;
		int upperBound		= 1200; 
		int upperIllegal	= 75000;
		
		return doBoundIntInputWithDistribution( lowerBound, lowerIllegal, upperBound, upperIllegal, 0.05 );
		
//		int lowerBound	= -100;
//		int upperBound	= 5000;
//		
//		return this.doBoundIntInput( lowerBound, upperBound );
	}
	
	private int doArgument_2_Input(){
		int[] fixedInt		= {0, 1};
		
		return doFixedIntInputWithDistribution( fixedInt, 0.025 );
//		int[] illegalInt	= {-1, 2, };
//		
//		return this.doFixedIntInput(fixedInt, illegalInt, 11);
	}
	
	private int doArgument_3_Input(){
		int[] fixedInt		= {0, 1};
		return doFixedIntInputWithDistribution( fixedInt, 0.025 );
//		int[] illegalInt	= {-1, 2};
//		
//		return this.doFixedIntInput(fixedInt, illegalInt, 11);
	}
	
	private int doArgument_4_Input(){
		int lowerBound		= 0;
		int lowerIllegal	= -100;
		int upperBound		= 5000; 
		int upperIllegal	= 150000;
		
		return doBoundIntInputWithDistribution( lowerBound, lowerIllegal, upperBound, upperIllegal, 0.05 );
//		int lowerBound	= -100;
//		int upperBound	= 5000;
//		
//		return this.doBoundIntInput( lowerBound, upperBound );
	}
	
	private int doArgument_5_Input(){
		int lowerBound		= 0;
		int lowerIllegal	= -100;
		int upperBound		= 1200; 
		int upperIllegal	= 75000;
		
		return doBoundIntInputWithDistribution( lowerBound, lowerIllegal, upperBound, upperIllegal, 0.90 );
		
//		int lowerBound	= -100;
//		int upperBound	= 1500;
//		
//		return this.doBoundIntInput( lowerBound, upperBound );
	}
	
	private int doArgument_6_Input(){
		return doArgument_4_Input();
//		int lowerBound	= -100;
//		int upperBound	= 1500;
//		
//		return this.doBoundIntInput( lowerBound, upperBound );
	}
	
	private int doArgument_7_Input(){
		int[] fixedInt		= {0, 1, 2, 3};

		return doFixedIntInputWithDistribution( fixedInt, 0.025 );
		
//		int[] fixedInt		= {0, 1, 2, 3};
//		int[] illegalInt	= {-1, 4, 9};
//		int randomSeed		= 21;		
//		return this.doFixedIntInput(fixedInt, illegalInt, randomSeed);
	}
	
	private int doArgument_8_Input(){
		int lowerBound		= 0;
		int lowerIllegal	= -100;
		int upperBound		= 1200; 
		int upperIllegal	= 75000;
		
		return doBoundIntInputWithDistribution( lowerBound, lowerIllegal, upperBound, upperIllegal, 0.1 );
//		int lowerBound	= -100;
//		int upperBound	= 10;
//		
//		return this.doBoundIntInput(lowerBound, upperBound);
	}
	
	private int doArgument_9_Input(){

		int lowerBound		= 0;
		int lowerIllegal	= -100;
		int upperBound		= 1200; 
		int upperIllegal	= 75000;
		
		return doBoundIntInputWithDistribution( lowerBound, lowerIllegal, upperBound, upperIllegal, 0.1 );
		
//		int lowerBound	= -100;
//		int upperBound	= 10;
//		return this.doBoundIntInput(lowerBound, upperBound);		
	}
	
	private int doArgument_10_Input(){
		int[] fixedInt		= {0, 1, 2};

		return doFixedIntInputWithDistribution( fixedInt, 0.025 );
//		
//		int[] fixedInt		= {0, 1, 2};
//		int[] illegalInt	= {-1, 3, 4, 9};
//		int randomSeed		= 16;
//		
//		return this.doFixedIntInput(fixedInt, illegalInt, randomSeed);
	}
	
	private int doArgument_11_Input(){
		int[] fixedInt		= {1, 2};
		
		return doFixedIntInputWithDistribution( fixedInt, 0.025 );
		
//		int[] fixedInt		= {1, 2};
//		int[] illegalInt	= {0, 3};
//		int randomSeed		= 11;
//		
//		return this.doFixedIntInput(fixedInt, illegalInt, randomSeed);
	}
	
	private int doArgument_12_Input(){
		int[] fixedInt		= {0, 1};
		
		return doFixedIntInputWithDistribution( fixedInt, 0.025 );
		
//		int[] fixedInt		= {0, 1};		
//		int[] illegalInt	= {-1, 2, 4, 9};
//		int randomSeed		= 11;
//		
//		return this.doFixedIntInput(fixedInt, illegalInt, randomSeed);
	}
}
